package com.lyn.config;

import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.WallFilter;
import com.feizhou.swagger.config.routes.SwaggerRoutes;
import com.jfinal.config.*;
import com.jfinal.ext.handler.ContextPathHandler;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.dialect.*;
import com.jfinal.plugin.cron4j.Cron4jPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.redis.RedisPlugin;
import com.jfinal.plugin.redis.serializer.ISerializer;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import com.lyn.demo.BatchController;
import com.lyn.demo.RedisController;
import com.lyn.demo.SwaggerDemoController;
import com.lyn.domain._MappingKit;
import com.lyn.hy.HyydflbController;
import com.lyn.log.log4j2.Slf4jLogFactory;
import com.lyn.mango.MangoController;
import com.lyn.system.controller.UserController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.util.SafeEncoder;

import java.sql.Connection;
import java.time.Duration;

//import com.jfinal.template.source.ClassPathSourceFactory;


public class ProjectConfig extends JFinalConfig {
    Logger logger = LoggerFactory.getLogger(ProjectConfig.class);

    private static Prop p = PropKit.use("application-local.properties");
            //.appendIfExists("audit-prod.properties");

    private WallFilter wallFilter;

    private DruidPlugin druidPlugin;

    public static void main(String[] args) {

        UndertowServer.start(ProjectConfig.class, 8081, true);
        //JFinal.start("src/main/webapp", 8081, "/", 5);
    }



    public void configConstant(Constants me) {
        me.setDevMode(p.getBoolean("devMode", false));
        me.setJsonFactory(MixedJsonFactory.me());

        //使用log4j2作为日志框架
        me.setLogFactory(new Slf4jLogFactory());
    }

    public void configRoute(Routes me) {
        //me.setBaseViewPath("/static");
        me.add("/swaggerDemo", SwaggerDemoController.class);
        me.add("/batch", BatchController.class);

        me.add("/user", UserController.class);
        me.add("/redis", RedisController.class);

        me.add("/mango", MangoController.class);
        me.add("/report/hy", HyydflbController.class);

        me.add(new SwaggerRoutes());
    }

    public void configEngine(Engine me) {
        me.setDevMode(p.getBoolean("engineDevMode", false));
    }



    public void configPlugin(Plugins me) {
        //me.add(new EhCachePlugin());
        initActiveRecord(me);

        //initCron4j(me);
        //initRedis(me);

    }
    public void configInterceptor(Interceptors me) {}
    public void configHandler(Handlers me) {
        me.add(new ContextPathHandler("basePath"));
    }

    public void afterJFinalStart() {
        // 让 druid 允许在 sql 中使用 union
        // https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE-wallfilter
        //wallFilter.getConfig().setSelectUnionCheck(false);
        initMango();
        logger.info("我的输出：启动完成！");
    }

    public void initActiveRecord(Plugins me) {
        druidPlugin = new DruidPlugin(p.get("datasource.url"), p.get("datasource.username"),
                p.get("datasource.password").trim(), p.get("datasource.driver"));

        // 配置log插件
        druidPlugin.setConnectionProperties("druid.timeBetweenLogStatsMillis="
                + Duration.ofHours(24).toMillis());
        Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
        slf4jLogFilter.setDataSourceLogEnabled(false);
        slf4jLogFilter.setConnectionLogEnabled(false);
        slf4jLogFilter.setConnectionLogErrorEnabled(true);
        slf4jLogFilter.setStatementLogEnabled(false);
        slf4jLogFilter.setStatementLogErrorEnabled(true);
        slf4jLogFilter.setResultSetLogEnabled(false);
        slf4jLogFilter.setResultSetLogErrorEnabled(true);
        slf4jLogFilter.setConnectionConnectBeforeLogEnabled(false);
        slf4jLogFilter.setConnectionConnectAfterLogEnabled(false);
        slf4jLogFilter.setConnectionCommitAfterLogEnabled(false);
        slf4jLogFilter.setConnectionRollbackAfterLogEnabled(true);
        slf4jLogFilter.setConnectionCloseAfterLogEnabled(false);
        slf4jLogFilter.setStatementCreateAfterLogEnabled(false);
        slf4jLogFilter.setStatementPrepareAfterLogEnabled(false);
        slf4jLogFilter.setStatementPrepareCallAfterLogEnabled(false);
        slf4jLogFilter.setStatementExecuteAfterLogEnabled(false);
        slf4jLogFilter.setStatementExecuteQueryAfterLogEnabled(false);
        slf4jLogFilter.setStatementExecuteUpdateAfterLogEnabled(false);
        slf4jLogFilter.setStatementExecuteBatchAfterLogEnabled(false);
        slf4jLogFilter.setStatementCloseAfterLogEnabled(false);
        slf4jLogFilter.setStatementParameterSetLogEnabled(false);
        slf4jLogFilter.setResultSetNextAfterLogEnabled(false);
        slf4jLogFilter.setResultSetOpenAfterLogEnabled(false);
        slf4jLogFilter.setResultSetCloseAfterLogEnabled(false);
        slf4jLogFilter.setStatementExecutableSqlLogEnable(true);
        druidPlugin.addFilter(slf4jLogFilter);

        // 配置druid wall，加强数据库安全
        wallFilter = new WallFilter();
        String url = p.get("datasource.url");
        Dialect dialect = null;
        if(url.toLowerCase().contains(JdbcConstants.ORACLE)){
            dialect = new OracleDialect();
            druidPlugin.setValidationQuery("select 1 from dual");
            wallFilter.setDbType("oracle");
        }
        else if(url.toLowerCase().contains(JdbcConstants.SQL_SERVER)){
            dialect = new AnsiSqlDialect();
        }
        else if(url.toLowerCase().contains(JdbcConstants.MYSQL)){
            dialect = new MysqlDialect();
            wallFilter.setDbType("mysql");
        }
        else if(url.toLowerCase().contains(JdbcConstants.POSTGRESQL)){
            dialect = new PostgreSqlDialect();
        }
        else{
            throw new RuntimeException("不支持的数据库！");
        }
        druidPlugin.addFilter(wallFilter);

        //配置druid的web统计程序
        StatFilter statFilter = new StatFilter();
        statFilter.setMergeSql(true);
        statFilter.setLogSlowSql(true);
        druidPlugin.addFilter(statFilter);    // 添加 StatFilter 才会有统计数据
        druidPlugin.setConnectionProperties("druid.timeBetweenLogStatsMillis="
                + Duration.ofHours(24).toMillis());
        druidPlugin.addFilter(new StatFilter());

        me.add(druidPlugin);
        ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
        arp.setShowSql(true);
        arp.setDialect(dialect);
        arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));
        arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
        _MappingKit.mapping(arp);
        // 强制指定复合主键的次序，避免不同的开发环境生成在 _MappingKit 中的复合主键次序不相同
        //arp.setPrimaryKey("document", "mainMenu,subMenu");
        me.add(arp);
        //arp.setShowSql(p.getBoolean("devMode", false));
        //arp.getEngine().setSourceFactory(new ClassPathSourceFactory());
        //arp.addSqlTemplate("/sql/all_sqls.sql");
    }

    public void initCron4j(Plugins me) {
        //work ok
//      Cron4jPlugin cp = new Cron4jPlugin();
//      cp.addTask("* * * * *", new FirstTask());
//      cp.addTask("* * * * *", new SecondTask());
//      me.add(cp);

        Cron4jPlugin cp = new Cron4jPlugin("application-local.properties");
        me.add(cp);
    }

    public void initRedis(Plugins me) {
    // 用于缓存main模块的redis服务
        RedisPlugin bbsRedis = new RedisPlugin("bbs", "127.0.0.1");
        bbsRedis.setSerializer(new ISerializer() {
            @Override
            public byte[] keyToBytes(String key) {
                return SafeEncoder.encode(key);
            }
            @Override
            public String keyFromBytes(byte[] bytes) {
                return SafeEncoder.encode(bytes);
            }
            @Override
            public byte[] fieldToBytes(Object field) {
                return valueToBytes(field);
            }
            @Override
            public Object fieldFromBytes(byte[] bytes) {
                return valueFromBytes(bytes);
            }
            @Override
            public byte[] valueToBytes(Object value) {
                return SafeEncoder.encode(value.toString());
            }
            @Override
            public Object valueFromBytes(byte[] bytes) {
                if(bytes == null || bytes.length == 0)
                    return null;
                return SafeEncoder.encode(bytes);
            }
        });

        me.add(bbsRedis);
    }

    public void initMango() {
        Man.set(druidPlugin.getDataSource());
    }




}